package com.wontube.smr.bo.sites.vevo;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.apache.ibatis.session.SqlSession;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.wontube.client.extension.utils.StringUtils;
import com.wontube.core.dao.mybatis.QueryExample;
import com.wontube.core.utils.JsonUtils;
import com.wontube.smr.bo.constants.SiteConstants;
import com.wontube.smr.client.model.po.MVChart;
import com.wontube.smr.dao.mapper.MVChartMapper;
import com.wontube.smr.pub.DefaultDBHelper;


/**
 * vevo 排行榜 抓取
 * @author tanggf(2012-4-5)
 *
 */
public final class VevoChartSpider {
	private final static String POPULAR_TODAY= "MostViewedToday";
	private final static String POPULAR_WEEK = "MostViewedThisWeek";
	private final static String POPULAR_ALL_TIME = "MostViewedAllTime";	
	//private final static String VEVO_VIDIO_URL = "http://www.vevo.com/video/";
	private final static String VEVO_ARTIST_URL = "http://www.vevo.com/artist/";	
	
	private VevoChartSpider() {
	}	
	
	//top videos
	//order: MostViewedToday, MostViewedThisWeek, MostViewedAllTime
	// 按类别列出所有数据的地址
	// http://api.vevo.com/mobile/v1/video/list.json?order=mostviewedtoday&genres=&offset=0&max=200
	// 单项结果示例
	//	{
	//		"isrc":"USRV81200025",
	//		"title":"Honestly",
	//		"image_url":"http:\/\/img.cache.vevo.com\/Content\/VevoImages\/video\/5D3D6EF04BFA59249A8403A7D10B1CE3.jpg",
	//		"duration_in_seconds":223,
	//		"artists_main":[{"on_tour":true,"id":"b3303746-cfb2-4ddf-ac13-272e4c0a9334","name":"Hot Chelle Rae","image_url":"http:\/\/img.cache.vevo.com\/Content\/VevoImages\/artist\/3833E7BC0F0524C371569F288F9D833A.jpg","url_safename":"hot-chelle-rae","favoritecount":61,"video_count":0}],
	//		"artists_featured":[],
	//		"viewcount":1689450,
	//		"premiere":true,
	//		"explicit":false,
	//		"url_safe_title":"honestly"
	//	}
	private static final String topVideosFormat = "http://api.vevo.com/mobile/v1/video/list.json?order={}&offset={}&max={}";
	
	// artists 排行榜地址
	// http://api.vevo.com/mobile/v1/artist/list.json?order=MostViewedToday&offset=0&max=10
	// 单项结果示例
	//	{
	//		"on_tour":false,
	//		"id":"75f426ad-5e04-4f83-9dd5-88a9ca841201",
	//		"name":"Katy Perry",
	//		"image_url":"http:\/\/img.cache.vevo.com\/Content\/VevoImages\/artist\/034B158B901E09D877CFE3FC1CCEA361.jpg",
	//		"url_safename":"katy-perry",
	//		"favoritecount":2045,
	//		"video_count":45,
	//		"songkick_id":null,
	//		"bio":"",
	//		"homepage_url":"http:\/\/www.katyperry.com\/",
	//		"twitter_account":"katyperry",
	//		"buylinks":[{"vendor":"bravado","link_type":"merch","image_url":"http:\/\/cache.vevo.com\/assets\/bravado_merch.png","url":"http:\/\/store.vevo.com\/Store.aspx?cp=31093_35110_14398&src=VEVOKATY001"},{"vendor":"itunes","link_type":"mp3","image_url":"http:\/\/cache.vevo.com\/assets\/itunes_mp3.png","url":"http:\/\/click.linksynergy.com\/fs-bin\/click?id=\/vTjmg74bvE&subid=0&offerid=146261.1&type=10&tmpid=5573&RD_PARM1=http%3A%2F%2Fitunes.apple.com%2Fus%2Fartist%2Fkaty-perry%2Fid64387566"}],
	//		"viewcount":1133536720,
	//		"viewcount_yesterday":4232025,
	//		"viewcount_lastweek":35517652,
	//		"viewcount_lastmonth":75457534,
	//		"created_at":"2010-01-23T02:29:15Z",
	//		"modified_at":"2012-03-16T17:53:36Z"
	//	}
	private static final String topArtistsFormat = "http://api.vevo.com/mobile/v1/artist/list.json?order={}&offset={}&max={}";
	
	// http://api.vevo.com/mobile/v1/featured/TopVideos.json?max=20
	// 单项结果结构与list相同
	private static final String hotVideoFormat = "http://api.vevo.com/mobile/v1/featured/TopVideos.json?max={}";
	
	/**
	 * daily top video
	 * @return
	 */
	public static int grabDailyTopVideos(){		
		return grabTopVideosAndSave(POPULAR_TODAY, 
				MVChart.CATEGORY_VEVO_TOP_VIDEOS, MVChart.UPDATE_PERIOD_DAILY);
	}
	
	/**
	 * weekly top video
	 * @return
	 */
	public static int grabWeeklyTopVideos(){		
		return grabTopVideosAndSave(POPULAR_WEEK, 
				MVChart.CATEGORY_VEVO_TOP_VIDEOS, MVChart.UPDATE_PERIOD_WEEKLY);
	}
	
	/**
	 * all time top video
	 * @return
	 */
	public static int grabAllTimeTopVideos(){		
		return grabTopVideosAndSave(POPULAR_ALL_TIME, 
				MVChart.CATEGORY_VEVO_TOP_VIDEOS, MVChart.UPDATE_PERIOD_ALL_TIME);
	}
	
	/**
	 * daily top artist
	 * @return
	 */
	public static int grabDailyTopArtists(){		
		return grabTopArtistsAndSave(POPULAR_TODAY, 
				MVChart.CATEGORY_VEVO_TOP_ARTISTS, MVChart.UPDATE_PERIOD_DAILY);
	}
	
	/**
	 * weekly top artists
	 * @return
	 */
	public static int grabWeeklyTopArtists(){		
		return grabTopArtistsAndSave(POPULAR_WEEK, 
				MVChart.CATEGORY_VEVO_TOP_ARTISTS, MVChart.UPDATE_PERIOD_WEEKLY);
	}
	
	/**
	 * all time top artists
	 * @return
	 */
	public static int grabAllTimeTopArtists(){		
		return grabTopArtistsAndSave(POPULAR_ALL_TIME, 
				MVChart.CATEGORY_VEVO_TOP_ARTISTS, MVChart.UPDATE_PERIOD_ALL_TIME);
	}
	
	private static int grabTopVideosAndSave(String order, String category, String period){
		List<MVChart> musics = getTopVideos(order);
		save2db(musics, category, period);
		return musics.size();
	}
	
	private static List<MVChart> getTopVideos(String popular){
		int start = 0;
		int max = 100; //top 100
		String url = StringUtils.format(topVideosFormat, popular, start, max);
		return parseVideos(url);
	}
	
	private static int grabTopArtistsAndSave(String order, String category, String period){
		List<MVChart> musics = getTopArtists(order);
		save2db(musics, category, period);
		return musics.size();
	}
	
	private static List<MVChart> getTopArtists(String popular){
		int start = 0;
		int max = 100; //top 100
		String url = StringUtils.format(topArtistsFormat, popular, start, max);
		return parseArtists(url);
	}	
	
	/**
	 * 抓取staff picks排行榜
	 */
	public static int grabTopStaffPicks(){		
		int max = 20; //top 20
		String url = StringUtils.format(hotVideoFormat, max);
		//解析url
		List<MVChart> musics = parseVideos(url);				
		save2db(musics, MVChart.CATEGORY_VEVO_STAFF_PICKS, "");
		return musics.size();
	}
	

	/**
	 * 解析top artist结果
	 * @param url
	 * @return
	 */
	private static List<MVChart> parseArtists(String url) {
		List<MVChart> musicList = new ArrayList<MVChart>();
		JsonObject jsonObject = JsonUtils.getJsonObjectFromUrl(url);
		JsonArray result = jsonObject.getAsJsonArray("result");
		for (int i = 0; i < result.size(); i++) {
			jsonObject = (JsonObject) result.get(i);
			MVChart vo = new MVChart();					
			String urlSafeName = jsonObject.get("url_safename").getAsString();
			vo.setVideoId(urlSafeName);
			
			vo.setWebsite(SiteConstants.WEBSITE_VEVO);
			vo.setItemUrl(VEVO_ARTIST_URL + urlSafeName);			
			vo.setMovieId(SiteConstants.ID_PREFIX_VEVO + urlSafeName);			
			vo.setThumbnail(jsonObject.get("image_url").getAsString());
			String name = jsonObject.get("name").getAsString();
			vo.setTitle(name);		
			vo.setSinger(name);
			vo.setViewCount(jsonObject.get("viewcount").getAsLong());
			vo.setVideoCount(jsonObject.get("video_count").getAsInt());
			
			musicList.add(vo);
		}
		return musicList;
	}

	/**
	 * 解析video结果
	 * @pa
	 * ram url
	 * @return
	 */
	private static List<MVChart> parseVideos(String url) {
		List<MVChart> musicList = new ArrayList<MVChart>();
		JsonObject jsonObject = JsonUtils.getJsonObjectFromUrl(url);
		JsonArray result = jsonObject.getAsJsonArray("result");
		for (int i = 0; i < result.size(); i++) {
			MVChart vo = new MVChart();
			jsonObject = (JsonObject) result.get(i);
			String isrc = jsonObject.get("isrc").getAsString();
			vo.setVideoId(isrc);
			vo.setWebsite(SiteConstants.WEBSITE_VEVO);
			
			vo.setId(UUID.randomUUID().toString());
			vo.setMovieId(SiteConstants.ID_PREFIX_VEVO + isrc);
			
			vo.setThumbnail(jsonObject.get("image_url").getAsString());
			vo.setTitle(jsonObject.get("title").getAsString());
			JsonArray artists = jsonObject.getAsJsonArray("artists_main");
			StringBuilder sbActors = new StringBuilder();
			for (int j = 0; j < artists.size(); j++) {
				JsonObject artist = artists.get(j).getAsJsonObject();
				String actor = artist.get("name").getAsString();
				if (j > 0) {
					sbActors.append(",");
				}
				sbActors.append(actor);
			}
			vo.setSinger(sbActors.toString());
			vo.setViewCount(jsonObject.get("viewcount").getAsLong());
			
			if (artists.size() == 1) {
				JsonObject artist = artists.get(0).getAsJsonObject();
				String artistsUrl = artist.get("url_safename").getAsString();
				String nameUrl = jsonObject.get("url_safe_title").getAsString();
				String itemUrl = StringUtils.format("http://www.vevo.com/watch/{}/{}/{}", artistsUrl, nameUrl, isrc);
				vo.setItemUrl(itemUrl);
			} else {
				vo.setItemUrl("http://www.vevo.com/video/" + isrc);
			}
			
			musicList.add(vo);
		}
		return musicList;
	}
	

	/**
	 * 批量保存/更新数据
	 * @param musics
	 * @param category
	 * @param period
	 */
	private static void save2db(List<MVChart> charts, String category, String period) {
		int count = 0;
		// 时间戳
		Date now = Calendar.getInstance().getTime();
		
		// 批量session
		SqlSession session = DefaultDBHelper.getBatchSqlSession();		
		try {
			MVChartMapper mapper = session.getMapper(MVChartMapper.class);			
			for (MVChart chart : charts) {				
				chart.setCategory(category);
				chart.setUpdatePeriod(period);					
				chart.setVersion(now);
				chart.setSortIndex(++count);
				
				// category, update_period, video_id决定唯一性
				String videoId = chart.getVideoId();
				QueryExample ex = new QueryExample();
				ex.or().addCriterion("mv_chart.video_id=", videoId)
						.addCriterion("mv_chart.category=", category)
						.addCriterion("mv_chart.update_period=", period);
				List<MVChart> musics = mapper.selectByExample(ex);
				if (musics.size() > 0) {
					// update					
					chart.setId(musics.get(0).getId());
					mapper.updateByPrimaryKey(chart);
				} else {
					// insert		
					chart.setId(UUID.randomUUID().toString());
					mapper.insert(chart);
				}
			}
			
			session.commit();
		} finally {
			session.close();
		}
	}
}
